﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using Foothill.Common;
using Foothill.IoC;
using Foothill.Model;
using Foothill.Service.AdService;
using Foothill.Service.Caching;
using Foothill.Service.MiscInfo;
using Foothill.Service.Security;
using Foothill.Service.Session;
using Foothill.Service.UserAccount;
using Foothill.Service.VehicleInfo;

namespace Foothill.Web
{
    public partial class ForSaleList : FoothillBasePage
    {
        private IAdService _adService;
        private IAdSearchService _adSearchService;
        private ISessionService _sessionService;
        private IVehicleInfoService _vehicleInfoService;
        private IMiscInfoService _miscInfoService;
        private IUserContextService _userContextService;
        private IUserAccountService _userAccountService;
        private ILocalCache _localCache;
        private IReorderService _reorderService;
        private ISecurityService _securityService;

        private int _loginUserId = -1;
        private CurrentLoginUser _currentLoginUser;

        private CurrentLoginUser currentUser
        {
            get
            {
                if (_currentLoginUser == null)
                {
                    _currentLoginUser = _securityService.GetLoginUserDetails();
                }

                return _currentLoginUser;
            }
        }

        private int _currentLoginUserId
        {
            get
            {
                if (_loginUserId < 0)
                {
                    _loginUserId = _securityService.GetLoginUserId();
                }

                return _loginUserId;
            }
        }

        private int _currentPage
        {
            set
            {
                ViewState["CurrentPage"] = value;
            }

            get
            {
                object obj = ViewState["CurrentPage"];
                return (obj == null) ? 1 : (int)obj;
            }
        }

        public int CurrentDisplayListSize
        {
            set
            {
                ViewState["CurrentDisplayListSize"] = value;
                ListPager.RecordCount = value;
                TopListPager.RecordCount = value;
            }

            get
            {
                return ConvertToInt(ViewState["CurrentDisplayListSize"]);
            }
        }

        public string PageSize
        {
            get
            {
                return GlobalSettings.AdListPageSize.ToString();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            _sessionService = IocContainer.GetInstance<ISessionService>();
            _vehicleInfoService = IocContainer.GetInstance<IVehicleInfoService>();
            _miscInfoService = IocContainer.GetInstance<IMiscInfoService>();
            _adService = IocContainer.GetInstance<IAdService>();
            _adSearchService = IocContainer.GetInstance<IAdSearchService>();
            _userContextService = IocContainer.GetInstance<IUserContextService>();
            _localCache = IocContainer.GetInstance<ILocalCache>();
            _reorderService = IocContainer.GetInstance<IReorderService>();
            _securityService = IocContainer.GetInstance<ISecurityService>();
            _userAccountService = IocContainer.GetInstance<IUserAccountService>();

            if (!IsPostBack)
            {
                CleanupDataInSession();
                InitCurrentLoginUser();
                InitPage();
                InitAdList();
            }
        }

        private void InitCurrentLoginUser()
        {
            if (_securityService.IsCurrentUserAuthenticated())
            {
                currentUser.SavedPostIdList = _adService.GetUserSavedPosts(_currentLoginUserId).Select(p => p.AdId).ToList();
            }
        }

        private void InitPage()
        {
            InitQuickSearchControls();
            InitOrderByDropDownList();
            gvwAdList.PageSize = GlobalSettings.AdListPageSize;
            ListPager.PageSize = GlobalSettings.AdListPageSize;
            TopListPager.PageSize = GlobalSettings.AdListPageSize;
        }

        // initiate the quick search controls on the top of the page
        private void InitQuickSearchControls()
        {
            AddItemsToDropDownList(ddlMake, _vehicleInfoService.GetVehicleMakes());

            ddlMake.SelectedIndex = 0;

            PopulateModelsList(Convert.ToInt32(ddlMake.SelectedItem.Value));

            AddItemsToDropDownList(ddlPrice, _miscInfoService.GetPriceRangeDict());
            ddlPrice.SelectedValue = ((int)PriceRange.Any).ToString();
            AddItemsToDropDownList(ddlPriceTo, _miscInfoService.GetPriceRangeDict());
            ddlPriceTo.SelectedValue = ((int)PriceRange.Any).ToString();

            AddItemsToDropDownList(ddlMileage, _miscInfoService.GetMileageRangeDict());
            ddlMileage.SelectedValue = ((int)MileageRange.Any).ToString();          
        }

        private void InitOrderByDropDownList()
        {
            IDictionary<int, string> dict = _reorderService.GetOrderByListItems();
            AddItemsToDropDownList(ddlOrderBy, dict);
        }

        // get ForSaleAdAdvancedSearchParameter from session
        private ForSaleAdAdvancedSearchParameter GetSearchParameterFromSession()
        {
            ForSaleAdAdvancedSearchParameter result = null;
            
            object o = _sessionService.GetSessionValue(SessionNames.ForSaleAdvancedSearchParam);

            if (o != null)
            {
                result = o as ForSaleAdAdvancedSearchParameter;
            }
            else
            {
                // when session is lost, reload the page
                Response.Redirect(Request.RawUrl);
            }

            return result;
        }

        private void InitAdList()
        {
            // see if the request is redirected from advanced search
            object o = Request.QueryString[GlobalQueryString.AdvSearchQsName];

            if (o != null)
            {
                string qsValue = o.ToString();  

                if (qsValue == GlobalQueryString.AdvSearchQsValue)
                {
                    // redirect from advanced search page
                    o = _sessionService.GetSessionValue(SessionNames.ForSaleAdvancedSearchParam);

                    if (o != null)
                    {
                        ForSaleAdAdvancedSearchParameter param = o as ForSaleAdAdvancedSearchParameter;

                        // display one page of ad on the gridview
                        DisplayAdList(param); 
                    }
                    else
                    {
                        // somehow, the session value is not there
                        DisplayDefaultList();
                    }
                }
            }
            else
            {
                // not redirected from advanced search page, display default list
                DisplayDefaultList();
            }

            // set the current page to page 1
            _currentPage = 1;
        }

        // when search parameter is in the session, it is redirected from user advanced search
        private void DisplayAdList(ForSaleAdAdvancedSearchParameter searchParam)
        {
            AdvancedSearchResult searchResult = _adSearchService.AdvancedSearch(searchParam);
            
            // save the search result list 
            _sessionService.AddSessionValue(SessionNames.CompleteSearchResultList, searchResult.CompleteResultList);
            
            gvwAdList.DataSource = _adSearchService.GetOnePage(searchResult.CompleteResultList, searchParam.PageNum, searchParam.PageSize);
            gvwAdList.DataBind();

            DisplayStats(searchResult);
            UpdateTotalNumOfPosts(searchResult.TotalNumberOfPost);
        }

        // when search parameter is missing, search using default criteria
        private void DisplayDefaultList()
        {
            ForSaleAdAdvancedSearchParameter searchParam = _adSearchService.ConstructDefaultSearchParameter();

            // save the default search parameter to session
            _sessionService.AddSessionValue(SessionNames.ForSaleAdvancedSearchParam, searchParam);
            
            // by default, display recent active posts
            AdvancedSearchResult searchResult = _adSearchService.AdvancedSearch(searchParam);

            // save the search result list 
            _sessionService.AddSessionValue(SessionNames.CompleteSearchResultList, searchResult.CompleteResultList);

            gvwAdList.DataSource = _adSearchService.GetOnePage(searchResult.CompleteResultList, searchParam.PageNum, searchParam.PageSize);
            gvwAdList.DataBind();

            DisplayStats(searchResult);
            PopulateSelectedMakeIdListIfNecessary(searchParam, searchResult.MakeStatsList);
            UpdateTotalNumOfPosts(searchResult.TotalNumberOfPost);
        }

        protected void gvwGroupByStatsOnRowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                DisplayStatsItem(e, "cbxGroupName", "lblCount");
            }
        }

        private void DisplayStats(AdvancedSearchResult searchResult)
        {
            DisplayCategoryStats(AdListCategory.Make, searchResult.MakeStatsList);

            DisplayCategoryStats(AdListCategory.City, searchResult.CityStatsList);

            DisplayCategoryStats(AdListCategory.Condition, searchResult.ConditionStatsList);

            DisplayCategoryStats(AdListCategory.ListingType, searchResult.ListingTypeStatsList);

            DisplayCategoryStats(AdListCategory.TransmissionType, searchResult.TransmissionTypeStatsList);

            DisplayCategoryStats(AdListCategory.Mileage, searchResult.MileageStatsList);

            DisplayCategoryStats(AdListCategory.YearAge, searchResult.YearAgeStatsList);
        }

        private void DisplayCategoryStats(AdListCategory category, IList<StatsItem> statsList)
        {
            GridView gridView = GetGridViewForAdListCategory(category);

            gridView.DataSource = statsList;
            gridView.DataBind();
        }

        // figure out specific make Id's are included in the result set when IncludeAllMake == true
        // without specific makes, filtering on makes won't work
        private void PopulateSelectedMakeIdListIfNecessary(ForSaleAdAdvancedSearchParameter param, IList<StatsItem> makeStatsItems)
        {
            if (param.IncludeAllMakes == true)
            {
                param.IncludeAllMakes = false;

                foreach (StatsItem item in makeStatsItems)
                {
                    param.AddMakeAndModel(item.GroupId, GlobalValues.AllModelId);
                }
            }

            _sessionService.SaveSessionValue(SessionNames.ForSaleAdvancedSearchParam, param);
        }

        private GridView GetGridViewForAdListCategory(AdListCategory adListCategory)
        {
            GridView gridView = gvwGroupByCity;
            switch (adListCategory)
            {
                case AdListCategory.City:
                    gridView = gvwGroupByCity;
                    break;
                case AdListCategory.Condition:
                    gridView = gvwGroupByCondition;
                    break;
                case AdListCategory.ListingType:
                    gridView = gvwGroupByListingType;
                    break;
                case AdListCategory.TransmissionType:
                    gridView = gvwGroupByTransmission;
                    break;
                case AdListCategory.Make:
                    gridView = gvwGroupByMakes;
                    break;
                case AdListCategory.Mileage:
                    gridView = gvwGroupByMileage;
                    break;
                case AdListCategory.YearAge:
                    gridView = gvwGroupByYearAge;
                    break;
            }

            return gridView;
        }
        
        // quick search
        protected void btnQuickSearch_Click(object sender, EventArgs e)
        {
            int selectedMileageRange = Convert.ToInt32(ddlMileage.SelectedValue);
            int maxMilage = _miscInfoService.GetMaxMileageNumber((MileageRange)selectedMileageRange);

            PriceRange priceFrom = (PriceRange)Convert.ToInt32(ddlPrice.SelectedValue);
            PriceRange priceTo = (PriceRange)Convert.ToInt32(ddlPriceTo.SelectedValue);

            ForSaleAdAdvancedSearchParameter searchParams = _adSearchService.ConstructQuickSearchParameter(Convert.ToInt32(ddlMake.SelectedValue), Convert.ToInt32(ddlModel.SelectedValue), maxMilage, priceFrom, priceTo);

            // save the default search parameter to session
            _sessionService.AddSessionValue(SessionNames.ForSaleAdvancedSearchParam, searchParams);

            DisplayAdList(searchParams);        
        }

        protected void OrderByDesc(Object sender, EventArgs e)
        {
            ReorderDisplayList(GetSelectedOrderByItem(), fhSortDirection.DESC);
        }

        protected void OrderByAsc(Object sender, EventArgs e)
        {
            ReorderDisplayList(GetSelectedOrderByItem(), fhSortDirection.ASC);
        }

        private OrderByItems GetSelectedOrderByItem()
        {
            if (string.IsNullOrEmpty(ddlOrderBy.SelectedValue))
            {
                return OrderByItems.ByPrice;
            }

            int selectedId = 0;

            if (int.TryParse(ddlOrderBy.SelectedValue, out selectedId))
            {
                return (OrderByItems)selectedId;  
            }

            return OrderByItems.ByPrice;
        }

        private void ReorderDisplayList(OrderByItems orderByItem, fhSortDirection sortDirection)
        {
            IList<ForSaleAd> reorderedList = _reorderService.ReorderSearchResultList(orderByItem, sortDirection, GetDisplayedResultList());

            _sessionService.SaveSessionValue(SessionNames.DisplaySearchResultList, reorderedList);
            SaveOrderByOptionsToSession(orderByItem, sortDirection);

            ChangePage(_currentPage);
        }

        private void SaveOrderByOptionsToSession(OrderByItems orderByItem, fhSortDirection sortDirection)
        {
            ForSaleAdAdvancedSearchParameter searchParam = GetSearchParameterFromSession();

            searchParam.OrderByItem = orderByItem;
            searchParam.SortDirection = sortDirection;

            _sessionService.SaveSessionValue(SessionNames.ForSaleAdvancedSearchParam, searchParam);
        }

        public void ChangePage(int pageNumber)
        {
            if (pageNumber < 1)
            {
                pageNumber = 1;
            }
            
            ForSaleAdAdvancedSearchParameter param = GetSearchParameterFromSession();
            param.PageNum = pageNumber;

            IList<ForSaleAd> displayList = GetDisplayedResultList();

            gvwAdList.DataSource = _adSearchService.GetOnePage(displayList, param.PageNum, param.PageSize);
            gvwAdList.DataBind();
        }

        protected void ListPagerPageChanged(object src, EventArgs e)
        {
            ChangePage(ListPager.CurrentPageIndex);
        }

        protected void TopListPagerPageChanged(object src, EventArgs e)
        {
            ChangePage(TopListPager.CurrentPageIndex);
        }

        private IList<ForSaleAd> GetDisplayedResultList()
        {
            // get the DisplaySearchResultList first, if null, get CompleteSearchResultList
            object obj = _sessionService.GetSessionValue(SessionNames.DisplaySearchResultList);

            if (obj == null)
            {
                obj = _sessionService.GetSessionValue(SessionNames.CompleteSearchResultList);
            }

            IList<ForSaleAd> result = obj as IList<ForSaleAd>;

            if (result == null)
            {
                // when session is lost, reload the page
                Response.Redirect(Request.RawUrl);
            }

            return result;
        }
    }
}
